package turtle.system.invest.evaluate;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;

import org.osite.util.FileResourceLoader;
import org.osite.util.Preconditions;
import org.osite.util.ResourceLoader;
import org.osite.util.ToolKit;
import org.osite.xml.XmlMember;
import org.osite.xml.XmlParser;
import org.osite.xml.XmlUtil;
import org.w3c.dom.Document;

import turtle.system.invest.Environment;
import turtle.system.invest.rule.InvestRunnable;
import turtle.system.invest.rule.Rule;
import turtle.system.invest.rule.WinnieRule;

public class Simulate {
    private Environment environment = new Environment();

    private final ArrayList<InvestRunnable> setupTasks = ToolKit.newArrayList();
    private final ArrayList<InvestRunnable> postTasks = ToolKit.newArrayList();

    private Rule rule;

    public static final String END_TIMESTAMP = makeKey("endTimestamp");
    public static final String START_TIMESTAMP = makeKey("startTimestamp");
    
    public void setEnvironment(Environment env) {
    	this.environment = Preconditions.checkNotNull(env);
    }
    
    @XmlMember
    public void addSetupTasks(InvestRunnable[] tasks) {
        setupTasks.addAll(Arrays.asList(tasks));
    }

    @XmlMember
    public void addPostTasks(InvestRunnable[] tasks) {
        postTasks.addAll(Arrays.asList(tasks));
    }

    @XmlMember(identifyByType = true)
    public void setRule(Rule rule) {
        this.rule = Preconditions.checkNotNull(rule);
    }

    private void runTasks(ArrayList<InvestRunnable> tasks) {
        for (InvestRunnable task : tasks) {
            task.run(environment);
        }
        tasks.clear();
    }

    public void run(ResourceLoader loader) {
        environment.setResourceLoader(loader);
        
        double fee = Double.parseDouble(environment.get("Fee", "0"));
        double taxRate = Double.parseDouble(environment.get("TaxRate", "0"));
        environment.resetInvestHistory().setFeeAndTaxRate(fee, taxRate);
        
        runTasks(setupTasks);
        
        Rule rule = this.rule;
        rule.setup(environment);

        int s = environment.get(START_TIMESTAMP, 0);
        int e = environment.get(END_TIMESTAMP, 0);
        for (;s < e; ++s) {
            environment.setTimestamp(s);
            rule.exercise(environment, s);
        }
        
        runTasks(postTasks);
    }

    public static String makeKey(String name) {
        return "org.osite.invest" + name;
    }

    public static void main(String argv[]) throws Exception {
        XmlParser parser = new XmlParser()
                .addDefaultAttributeConvertors()
                .registerComponent(Simulate.class)
                .registerComponent(PrintProfit.class)
                .registerComponent(IndexBuilder.class)
                .registerComponent(TimestampSetter.class)
                .registerComponent(WinnieRule.class)
                .registerComponent(SetVariable.class);
        ResourceLoader resourceLoader = new FileResourceLoader(new File("."));
        Document doc = XmlUtil.parseDocument(
                resourceLoader.getResource("simulate.xml"));
        Simulate simulate = (Simulate) parser.parse(doc.getDocumentElement());
        simulate.run(resourceLoader);
    }
}
